<template>
  <el-dropdown ref="dropdownRef" placement="bottom-start" trigger="click" style="width: 100%"
    @visible-change="handleVisibleChange">
    <el-input ref="inputRef" v-model="iconValue" :placeholder="placeholder" style="width: 100%" v-bind="attrs" readonly>
      <template v-if="iconValue && iconShow" #prepend>
        <ClIcon color="grey" :size="20" :componentName="iconValue">
        </ClIcon>
      </template>
      <template #suffix>
        <span v-if="!attrs.disabled">
          <el-icon @click.stop="iconValue = undefined" v-if="iconValue" style="cursor: pointer">
            <CircleCloseFilled />
          </el-icon>
          <el-icon v-else>
            <ArrowDown />
          </el-icon>
        </span>
      </template>
    </el-input>
    <template #dropdown>
      <div class="icon_box" :style="{ width: iconBoxWidth }">
        <el-tabs v-model="activeIconType" @tab-change="handleTabChange" style="margin: 0 4px;">
          <el-tab-pane :label="item.type" :name="item.type" v-for="item in iconList">
            <div class="icon_list" :style="{ maxHeight }">
              <div v-for="(icon, idx) in item.list" :key="idx" :class="setIconClass(icon, idx, item.list)"
                @click="handleSelectIcon(icon)" :style="{
                  borderColor: iconValue === icon ? activeColor : 'gainsboro',
                }">
                <ClIcon :color="iconValue === icon ? activeColor : 'grey'" :size="iconSize" :componentName="icon">
                </ClIcon>
              </div>
              <div v-for="item in lastRowFillLength" :style="{ width: iconSize + 30 + 'px' }"></div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </template>
  </el-dropdown>
</template>

<script setup>
import ClIcon from './ClIcon.vue'
import { useAttrs, ref, onMounted, computed, watch } from 'vue'
import elementPlusIconList from './elementPlusIconData.js'
const props = defineProps({
  placeholder: {
    type: String,
    default: '请选择图标',
  },
  // 选中的颜色
  activeColor: {
    type: String,
    default: '#409eff',
  },
  iconSize: {
    type: Number,
    default: 20,
  },
  // 图标列表高度
  maxHeight: {
    type: String,
    default: '500px',
  },
  // 是否展示图标
  iconShow: {
    type: Boolean,
    default: true,
  },
  // 使用图标的方式
  // elementPlus: 使用element-plus的图标(默认)
  // custom: 使用自定义的图标列表，会使用customIconList字段
  // additional：在原element-plus的基础上添加自定义的图标列表
  useIconMethod: {
    type: String,
    default: 'elementPlus',
  },
  // 使用自定义的icon列表
  customIconList: {
    type: Array,
    default: () => [],
  },
  // 是否点击后自动关闭
  autoClose: {
    type: Boolean,
    default: true,
  },
  // 关闭之前的回调
  beforeClose: {
    type: Function,
    default: null,
  },
  // 获取图标之前的格式化操作
  beforeGetIcon: {
    type: Function,
    default: null,
  },
  iconFontUrl: {
    type: String,
    default: '',
  },
  loadIconUrlOk: {
    type: Function,
    default: null,
  },
  loadIconUrlFail: {
    type: Function,
    default: null,
  },
})

const iconList = computed(() => {
  let resIconList = []
  if (props.useIconMethod === 'elementPlus') {
    // 如果使用自定义的图标列表，则直接返回
    resIconList = elementPlusIconList
  } else if (props.useIconMethod === 'custom') {
    resIconList = props.customIconList
  } else if (props.useIconMethod === 'additional') {
    // 如果是additional，则将elementPlusIconList和customIconList合并
    resIconList = [...elementPlusIconList, ...props.customIconList]
  }
  return props.beforeGetIcon ? props.beforeGetIcon(resIconList) : resIconList
})

const emits = defineEmits(['tab-change', 'icon-change'])
const activeIconType = ref()
const inputRef = ref()
const attrs = useAttrs()
const iconBoxWidth = ref('100%')
const iconValue = defineModel()
const lastRowFillLength = ref(0)
// 设置icon样式，加ClIconSelect前缀是预防类名重复
const setIconClass = (itm) => {
  let iconClass = 'icon_list_item ClIconSelect_icon_list_item'
  if (itm === iconValue.value) {
    iconClass += ' icon_list_item_active ClIconSelect_icon_list_item_active'
  }
  return iconClass
}

const dropdownRef = ref()
const handleSelectIcon = (icon) => {
  if (icon !== iconValue.value) {
    emits('icon-change', icon)
  }
  iconValue.value = icon
  if (props.autoClose) {
    dropdownRef.value.handleClose()
  } else {
    props.beforeClose && props.beforeClose(dropdownRef.value.handleClose)
  }
}

const handleTabChange = (val) => {
  fillLastRowIcon()
  emits('tab-change', val)
}
// 下拉显示隐藏
const handleVisibleChange = (visible) => {
  if (visible) {
    let inputEleWidth = inputRef.value.$el.offsetWidth
    iconBoxWidth.value = inputEleWidth + 'px'
    initIconType()
    fillLastRowIcon()
    // 延迟滚动到选中图标
    setTimeout(() => {
      scrollToSelectedIcon()
    }, 80)
  }
}

onMounted(() => {
  let inputEleWidth = inputRef.value.$el.offsetWidth
  iconBoxWidth.value = inputEleWidth + 'px'
})

// 填充最后一行的图标，使其左对其
const fillLastRowIcon = () => {
  let allNum = iconList.value.find(item => item.type === activeIconType.value).list.length
  let inputEleWidth = inputRef.value.$el.offsetWidth
  // 一个icon元素占用位置
  let iconEleWidth = props.iconSize + 30
  // 行的数量
  let rowNum = Math.floor(inputEleWidth / iconEleWidth)
  // 算出最后一行元素个数
  let yNum = allNum % rowNum
  if (yNum > 0) {
    // 如果最后一行有元素，则需要填充空白
    lastRowFillLength.value = rowNum - yNum
  }
}

// 元素初始化的时候回显操作
const initIconType = () => {
  if (iconValue.value) {
    // 如果有值，则需要设置activeIconType
    let iconType = iconList.value.find(item => item.list.includes(iconValue.value))
    if (iconType) {
      activeIconType.value = iconType.type
    }
  } else {
    // 如果没有值，则默认第一个类型
    activeIconType.value = iconList.value[0].type
  }
}

// 将选中值滚动到第一行
const scrollToSelectedIcon = () => {
  let iconEle = document.querySelector('.ClIconSelect_icon_list_item')
  if (iconValue.value) {
    iconEle = document.querySelector('.ClIconSelect_icon_list_item_active')
  }
  if (iconEle) {
    iconEle.scrollIntoView({ behavior: "instant", block: "start" })
  }
}

// 加载动态iconfont显示地址
const loadIconFontUrl = (url) => { 
  const existingScript = document.querySelector(`script .iconfont-symbol`);
  if (existingScript) {
    document.head.removeChild(existingScript);
  } else { 
    const scriptElement = document.createElement('script');
    scriptElement.src = url;
    scriptElement.type = 'text/javascript';
    scriptElement.onload = () => {
      props.loadIconUrlOk && props.loadIconUrlOk()
    };
    // 加载失败处理
    scriptElement.onerror = (error) => {
      props.loadIconUrlFail && props.loadIconUrlFail(error)
    };
    document.head.appendChild(scriptElement);
  }
}

watch(() => props.iconFontUrl, (newV) => {
  if (newV) {
    loadIconFontUrl(newV)
  }
}, {immediate: true})
</script>

<style lang="scss" scoped>
.icon_box {
  .icon_type {
    padding: 10px;
    font-size: 16px;
    font-weight: bold;
  }

  .icon_list {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    overflow-y: auto;

    &_item {
      margin: 4px;
      padding: 10px;
      border: 1px solid gainsboro;
      border-radius: 6px;
      cursor: pointer;
    }

    &_item:hover {
      box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.24);
    }

    // &::after {
    //   content: "";
    //   flex: 1;
    // }
  }
}
</style>
